package net.oschina.j2cache.cluster;

import net.oschina.j2cache.CacheException;
import net.oschina.j2cache.CacheProviderHolder;
import net.oschina.j2cache.lettuce.LettuceCacheProvider;
import net.oschina.j2cache.redis.RedisPubSubClusterPolicy;

import java.util.Properties;

/**
 * 集群策略工厂
 *
 * @author Winter Lau(javayou@gmail.com)
 */
public class ClusterPolicyFactory {

  private ClusterPolicyFactory() {}

  /**
   * 初始化集群消息通知机制
   *
   * @param holder CacheProviderHolder instance
   * @param broadcast j2cache.broadcast value
   * @param props broadcast configuations
   * @return ClusterPolicy instance
   */
  public static net.oschina.j2cache.cluster.ClusterPolicy init(CacheProviderHolder holder, String broadcast, Properties props) {

    net.oschina.j2cache.cluster.ClusterPolicy policy;
    if ("redis".equalsIgnoreCase(broadcast)) {
      policy = ClusterPolicyFactory.redis(props, holder);
    }else if ("lettuce".equalsIgnoreCase(broadcast)) {
      policy = ClusterPolicyFactory.lettuce(props, holder);
    } else if ("none".equalsIgnoreCase(broadcast)) {
      policy = new net.oschina.j2cache.cluster.NoneClusterPolicy();
    } else {
      policy = ClusterPolicyFactory.custom(broadcast, props, holder);
    }

    return policy;
  }

  /**
   * 使用 Redis 订阅和发布机制，该方法只能调用一次
   *
   * @param props 框架配置
   * @return 返回 Redis 集群策略的实例
   */
  private static net.oschina.j2cache.cluster.ClusterPolicy redis(Properties props, CacheProviderHolder holder) {
    String name = props.getProperty("channel");
    RedisPubSubClusterPolicy policy = new RedisPubSubClusterPolicy(name, props);
    policy.connect(props, holder);
    return policy;
  }

  private static net.oschina.j2cache.cluster.ClusterPolicy lettuce(Properties props, CacheProviderHolder holder) {
    LettuceCacheProvider policy = new LettuceCacheProvider();
    policy.connect(props, holder);
    return policy;
  }

  /**
   * 加载自定义的集群通知策略
   *
   * @param classname
   * @param props
   * @return
   */
  private static net.oschina.j2cache.cluster.ClusterPolicy custom(
      String classname, Properties props, CacheProviderHolder holder) {
    try {
      net.oschina.j2cache.cluster.ClusterPolicy policy = (net.oschina.j2cache.cluster.ClusterPolicy) Class.forName(classname).newInstance();
      policy.connect(props, holder);
      return policy;
    } catch (Exception e) {
      throw new CacheException("Failed in load custom cluster policy. class = " + classname, e);
    }
  }
}
